using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using MacomberMap.Common.Database_Interface;
using MacomberMap.Common.Database_Interface.CIM;
using System.Xml;
using System.IO;
using MacomberMap.Loader.Properties;
using MacomberMap.Common.Database_Interface.CIM.Components;
using MacomberMap.Loader.Export.OneLines;
using System.Drawing;
using System.Drawing.Imaging;
using Oracle.DataAccess.Client;

namespace MacomberMap.Loader.Export
{
    /// <summary>
    /// This class handles the bulk exporting of one-lines
    /// </summary>
    public class MM_Exporter_OneLine : MM_Exporter
    {
        #region Variable declarations
        /// <summary>
        /// Return the current progress
        /// </summary>
        public override float Progress
        {
            get { return Current / Total; }
        }
        /// <summary>
        /// The current step of export
        /// </summary>
        private float Current = 0;

        /// <summary>
        /// The total number of steps for export
        /// </summary>
        private float Total = 0;

        /// <summary>The XML configuration for our element</summary>
        private XmlElement xConfig;

        /// <summary>The ID of our last model</summary>
        private int LastModelID;

        /// <summary>Our oracle connection to the new system</summary>
        private OracleConnection oConn;

        /// <summary>The model's valid start date</summary>
        private DateTime ValidStart;
        #endregion

        #region Initialization
        /// <summary>
        /// Initialize our one-line exporter
        /// </summary>
        /// <param name="cDb"></param>
        /// <param name="oDb"></param>
        /// <param name="Parent"></param>
        /// <param name="xConfig"></param>        
        /// <param name="LastModelID"></param>
        /// <param name="ValidStart"></param>
        /// <param name="NewNMMS"></param>
        public MM_Exporter_OneLine(DateTime ValidStart, int LastModelID, XmlElement xConfig, ListView Parent, MM_Database_Oracle oDb, MM_Database_CIM cDb, OracleConnection  NewNMMS)
            : base(Parent, "One-Line Validation")
        {
            this.ValidStart = ValidStart;
            this.LastModelID = LastModelID;
            this.xConfig = xConfig;
            this.Total = MM_Database_CIM.ElementsOfType("cim:Substation").Count;
            this.oConn = NewNMMS;
        }

        /// <summary>
        /// Kick off our exporter
        /// </summary>
        public override void ProcessExporter()
        {
            String TargetDirectory = xConfig.Attributes["TargetDirectory"].Value.Replace("[ModelDirectory]", Path.GetDirectoryName(MM_Database_CIM.CIMFileName));
            if (!Directory.Exists(TargetDirectory))
                Directory.CreateDirectory(TargetDirectory);

            if (!File.Exists(Path.Combine(TargetDirectory, "ERCOTONELINES_ESET.DDL")))
                using (StreamWriter sW = new StreamWriter(Path.Combine(TargetDirectory, "ERCOTONELINES_ESET.DDL"), false, Encoding.ASCII))
                    sW.Write(Resources.ERCOTONELINES_ESET);

            String ImageDirectory = xConfig.Attributes["ImageDirectory"].Value.Replace("[ModelDirectory]", Path.GetDirectoryName(MM_Database_CIM.CIMFileName));
            if (!Directory.Exists(ImageDirectory))
                Directory.CreateDirectory(ImageDirectory);

            String MMExportDirectory = xConfig.Attributes["MMExportDirectory"].Value.Replace("[ModelDirectory]", Path.GetDirectoryName(MM_Database_CIM.CIMFileName));
            if (!Directory.Exists(MMExportDirectory))
                Directory.CreateDirectory(MMExportDirectory);

            //Now, open up our Oracle database for our new server
            using (StreamWriter sW = new StreamWriter(Path.Combine(TargetDirectory, "Update.log")))
            {
                sW.WriteLine("<?xml version=\"1.0\"?>");
                sW.WriteLine(String.Format("<OneLineProcessing Model=\"{0}\" LastModel=\"{1}\" RanOn=\"{1}\">", MM_Database_CIM.CIMFileName, LastModelID, XmlConvert.ToString(DateTime.Now, XmlDateTimeSerializationMode.Unspecified)));
                int TargetUser = 0;

                //Write out the entry for our new model
                int CurModel = 5;
                using (OracleCommand oCmd2 = new OracleCommand("INSERT INTO MM_DATABASE_MODEL (\"ID\", \"NAME\", \"EXPORTEDON\", \"VALIDSTART\", \"FULLPATH\", \"PRIORMODEL\", \"ELEMENTCOUNT\", \"TEIDCOUNT\", \"MAXTEID\", \"MAXMRID\") VALUES (SEQ_MM_DATABASE_MODEL.NEXTVAL, :1, :2, :3, :4, :5, :6, :7, :8, :9) RETURNING ID INTO :NewID", oConn))
                {
                    oCmd2.Prepare();
                    oCmd2.Parameters.Add(":1", Path.GetFileNameWithoutExtension(MM_Database_CIM.CIMFileName));
                    oCmd2.Parameters.Add(":2", File.GetCreationTime(MM_Database_CIM.CIMFileName));
                    oCmd2.Parameters.Add(":3", ValidStart);
                    oCmd2.Parameters.Add(":4", Path.GetDirectoryName(MM_Database_CIM.CIMFileName));
                    oCmd2.Parameters.Add(":5", LastModelID);
                    oCmd2.Parameters.Add(":6", MM_Database_CIM.Elements.Count);
                    oCmd2.Parameters.Add(":7", MM_Database_CIM.TEIDs.Count);
                    UInt64 MaxTEID = 0;
                    foreach (UInt64 TEID in MM_Database_CIM.TEIDs.Keys)
                        MaxTEID = Math.Max(TEID, MaxTEID);
                    oCmd2.Parameters.Add(":8", MaxTEID);
                    oCmd2.Parameters.Add(":9", MM_Database_CIM.MaxMRID);
                    OracleParameter oParam = oCmd2.Parameters.Add(":NewID", OracleDbType.Int32);
                    oParam.Direction = System.Data.ParameterDirection.Output;
                    oCmd2.ExecuteNonQuery();
                    CurModel = Convert.ToInt32(oParam.Value);
                }

                oConn.Open();

                //Now, go through each substation, and attempt to find our last model's representation
                foreach (CIM_Element SubElem in MM_Database_CIM.ElementsOfType("cim:Substation"))
                {
                    //Write out our new model
                    using (OracleCommand oCmd = new OracleCommand("SELECT ID FROM MM_DATABASE_ONELINE WHERE ONELINETYPE=:0 AND MODELS LIKE :1 AND TEID=:2", oConn))
                    {
                        oCmd.Prepare();
                        oCmd.Parameters.Add(":0", 0);
                        oCmd.Parameters.Add(":1", "," + LastModelID.ToString());
                        oCmd.Parameters.Add(":2", Convert.ToUInt64(SubElem.TEID));
                        using (OracleDataReader oRd = oCmd.ExecuteReader())
                            if (!oRd.Read())
                            {
                                sW.WriteLine(String.Format("\t<NotFound Substation=\"{0}\" TEID=\"{1}\" />", SubElem.Name, SubElem.TEID));
                                Console.WriteLine("Unable to find substation " + SubElem.Name);
                            }
                            else
                            {
                                int Errors = 0, Warnings = 0;
                                MM_Database_OneLine InLine = LoadOneLine(Convert.ToInt32(oRd["ID"]));
                                Image OneLineImage = LoadOneLineImage(Convert.ToInt32(oRd["ID"]));
                                Application.DoEvents();
                                String ValidationResult = "\n\t" + MM_OneLine_Validation.ValidateTopology(InLine.Document.DocumentElement, SubElem, CurModel, out Errors, out Warnings).Replace("\n", "\n\t") + "\n";
                                if (Errors == 0 && Warnings == 0)
                                {
                                    using (OracleCommand oCmd2 = new OracleCommand("UPDATE MM_DATABASE_ONELINE SET MODELS = MODELS || :0 WHERE ID=:1", oConn))
                                    {
                                        oCmd2.Prepare();
                                        oCmd2.Parameters.Add(":0", CurModel.ToString() + ",");
                                        oCmd2.Parameters.Add(":1", InLine.ID);
                                        oCmd2.ExecuteNonQuery();
                                    }
                                    sW.WriteLine(string.Format("\t<Success ID=\"{0}\" TEID=\"{1}\" SubName=\"{2}\"/>", InLine.ID, SubElem.TEID, SubElem.Name));
                                    MM_DDL_Exporter.ExportOneLine(InLine, CurModel, Path.Combine(TargetDirectory, "NETMOM-" + SubElem.Name + "_dset.ddl"), false, OneLineImage);
                                    MM_DDL_Exporter.ExportOneLine(InLine, CurModel, Path.Combine(TargetDirectory, "SCADAMOM-" + SubElem.Name + "_dset.ddl"), true, OneLineImage);
                                    Console.WriteLine("Success on " + String.Join(",", InLine.Names));
                                    using (Bitmap TempBitmap = new Bitmap(OneLineImage))
                                        TempBitmap.Save(Path.Combine(Path.Combine(TargetDirectory, "Images"), SubElem.Name + ".jpg"), ImageFormat.Jpeg);
                                }
                                else if (Errors == 0)
                                {
                                    sW.WriteLine(string.Format("\t<Warnings Warnings=\"{0}\" ID=\"{1}\" TEID=\"{2}\" SubName=\"{3}\">{4}</Warnings>", Warnings, InLine.ID, SubElem.TEID, SubElem.Name, ValidationResult));
                                    MM_DDL_Exporter.ExportOneLine(InLine, CurModel, Path.Combine(TargetDirectory, "NETMOM-" + SubElem.Name + "_dset.ddl"), false, OneLineImage);
                                    MM_DDL_Exporter.ExportOneLine(InLine, CurModel, Path.Combine(TargetDirectory, "SCADAMOM-" + SubElem.Name + "_dset.ddl"), true, OneLineImage);

                                    Console.WriteLine("Warning on " + String.Join(",", InLine.Names));
                                }
                                else
                                {
                                    int NewOneLineID = AssignOneLine(InLine, CurModel, SubElem, ValidationResult);
                                    sW.WriteLine(string.Format("\t<Errors Errors=\"{0}\" Warnings=\"{1}\" ID=\"{2}\" TEID=\"{3}\" SubName=\"{4}\">{5}</Errors>", Errors, Warnings, NewOneLineID, SubElem.TEID, SubElem.Name, ValidationResult));
                                    using (OracleCommand oCmd2 = new OracleCommand("INSERT INTO MM_DATABASE_ASSIGNMENT (\"ONELINE\", \"MODEL\", \"USER\", \"ASSIGNEDON\", \"NOTES\", ID) VALUES (:0, :1, :2, :3, :4, SEQ_MM_DATABASE_ASSIGNMENT.NEXTVAL)", oConn))
                                    {
                                        oCmd2.Prepare();
                                        oCmd2.Parameters.Add(":0", InLine.ID);
                                        oCmd2.Parameters.Add(":1", CurModel);
                                        oCmd2.Parameters.Add(":2", TargetUser);
                                        oCmd2.Parameters.Add(":3", DateTime.Now);
                                        oCmd2.Parameters.Add(":4", ValidationResult);
                                        oCmd2.ExecuteNonQuery();
                                    }
                                    TargetUser = (++TargetUser) % 5;
                                    Console.WriteLine("Error on " + String.Join(",", InLine.Names) + ":\n" + ValidationResult);
                                }

                                sW.Flush();
                            }
                        sW.WriteLine("</OneLineProcessing>");
                    }
                }


            }
        #endregion
        }

        private int AssignOneLine(MM_Database_OneLine InLine, int CurModel, CIM_Element SubElem, string ValidationResult)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        private Image LoadOneLineImage(int p)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        private MM_Database_OneLine LoadOneLine(int p)
        {
            throw new Exception("The method or operation is not implemented.");
        }
    }
}